﻿using Miao;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Xml;
using UnityEngine;
using static DirectXmlToObject;
using static UnityEngine.Rendering.DebugUI;

public static class DirectXmlToObject
{
    /// <summary>
    /// 存储将数据转成List的函数调用法
    /// </summary>
    private static Dictionary<Type, Func<XmlNode, object>> listFromXmlMethods = new Dictionary<Type, Func<XmlNode, object>>();

    private static readonly Dictionary<Type, Func<XmlNode, bool, object>> objectFromXmlMethods = new Dictionary<Type, Func<XmlNode, bool, object>>();
    //public static Func<XmlNode, bool, object> GetObjectFromXmlMethod(Type type)
    //{

    //}

    private static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfoLookup = new Dictionary<Type, Dictionary<string, FieldInfo>>();
    //原流程申请了一个反射类，不懂
    //原流程做了很多处理，这里精简一下
    //原流程的反射可能跟泛型有关系
    //解析xml数据是一个递归调用结构，一层一层解析

    /// <summary>
    /// 不使用泛型，而使用object的FieldType来确认类型返回
    /// </summary>
    /// <param name="xmlRoot"></param>
    /// <param name="field"></param>
    /// <returns></returns>
    public static object ObjectFromXml(XmlNode xmlRoot, Type field)
    {

        //判断进入Xml是否到底
        if (xmlRoot.ChildNodes.Count == 1 && xmlRoot.FirstChild.NodeType == XmlNodeType.CDATA)
        {
            return xmlRoot.FirstChild.Value;
        }
        if ((xmlRoot.ChildNodes.Count == 1 && xmlRoot.FirstChild.NodeType == XmlNodeType.Text))//解析xml到最底层
        {
            return ParseHelper.FromString(xmlRoot.InnerText, field);

        }
        if (field.HasGenericDefinition(typeof(List<>)))
        {
            return ListFromXml(xmlRoot, field);


        }
        if (field.HasGenericDefinition(typeof(Dictionary<,>)))
        {
            return DictionaryFromXml(xmlRoot, field);
        }
        xmlRoot = XmlInheritance.GetResolvedNodeFor(xmlRoot);

        object instance = Activator.CreateInstance(field);

        var customData = instance as ICustomDataFromXml;
        if (customData != null)
        {
            customData.LoadCustomXmlData(xmlRoot);
            return customData;
        }
        //查找要给实例对象赋值的类
        for (int i = 0; i < xmlRoot.ChildNodes.Count; i++)
        {
            XmlNode xmlNode = xmlRoot.ChildNodes[i];
            if (xmlNode is XmlComment)//跳过注释
            {
                continue;
            }

            //获得该名称的FieldInfo
            FieldInfo xmlField = GetFieldInfoForType(field, xmlNode.Name);
            if (xmlField == null)//如果为空，则证明没有找到特定字段，原项做了一个别名处理
            {
                Log.Error($"未在{field.Name}中找到{xmlNode.Name}字段");
            }
            else if (typeof(Def).IsAssignableFrom(xmlField.FieldType))//Def解析
            {
                if (string.IsNullOrEmpty(xmlNode.InnerText))
                {
                    xmlField.SetValue(instance, null);
                }
                XmlAttribute myRequire = xmlNode.Attributes["MayRequire"];//DLC用，用于标记DLC的可选运行时
                //Ref引用需要等所有Ref解析出来后反过来赋值
                DirectXmlCrossRefLoader.RegisterObjectWantsCrossRef(instance, xmlField, xmlNode.InnerText, myRequire?.Value);

            }
            else//递归查找
            {
                object obj = ObjectFromXml(xmlNode, xmlField.FieldType);

                if (!obj.GetType().IsValueType)
                {
                    xmlField.SetValue(instance, obj);//绑定值
                    continue;
                }
                object obj2 = instance;
                xmlField.SetValue(obj2, obj);
            }
        }
        return instance;
    }

    public delegate void RefListDelegate<T>(List<T> wanterList, string targetDefName, object debugWanterInfo = null, string mayRequireMod = null);
    static public Dictionary<IList, Delegate> ListCashe = new Dictionary<IList, Delegate>();
    /// <summary>
    /// 返回带有特定类型的回调
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="wanterList"></param>
    /// <param name="targetDefName"></param>
    /// <param name="debugWanterInfo"></param>
    /// <param name="mayRequireMod"></param>

    private static object ListFromXml(XmlNode listRootNode, Type listType)
    {
        IList list = Activator.CreateInstance(listType) as IList;
        Type listGenericType = listType.GenericTypeArguments[0];

        try
        {
            bool isDef = typeof(Def).IsAssignableFrom(listGenericType);
            if (isDef)
            {
                if (!ListCashe.TryGetValue(list, out Delegate refDelegate))
                {
                    MethodInfo methodFuc = MiaoGeneric.GetStaticGenericMethod(typeof(DirectXmlCrossRefLoader), nameof(DirectXmlCrossRefLoader.RegisterListWantsCrossRef), listGenericType);
                    //var parameter = methodFuc.GetParameters().Select(w => w.ParameterType).ToArray();
                    Type delegateType = typeof(RefListDelegate<>).MakeGenericType(listGenericType);
                    //因为结构和存储必须是泛型，所以必须使用动态调用
                    refDelegate = Delegate.CreateDelegate(delegateType, methodFuc);
                    ListCashe.Add(list, refDelegate);
                }
                //直接反射调用泛型方法，不缓存
                //MiaoGeneric.InvokeStaticGenericMethod(typeof(DirectXmlCrossRefLoader), listGenericType, nameof(DirectXmlCrossRefLoader.RegisterListWantsCrossRef),
                //list,childNode.InnerText, listRootNode.Name, xmlAttribute?.Value);
                //DirectXmlCrossRefLoader.RegisterListWantsCrossRef(list, childNode.InnerText, listRootNode.Name, xmlAttribute?.Value);

                foreach (XmlNode childNode in listRootNode.ChildNodes)
                {
                    XmlAttribute xmlAttribute = childNode.Attributes["MayRequire"];
                    refDelegate.DynamicInvoke(list, childNode.InnerText, listRootNode.Name, xmlAttribute?.Value);
                }
            }
            else
            {
                foreach (XmlNode childNode in listRootNode.ChildNodes)
                {
                    if (!ValidateListNode(childNode, listRootNode, listGenericType))
                    {
                        continue;
                    }

                    XmlAttribute xmlAttribute = childNode.Attributes["MayRequire"];
                    if (xmlAttribute == null || xmlAttribute.Value.NullOrEmpty() || ModsConfig.AreAllActive(xmlAttribute.Value))
                    {
                        try
                        {
                            list.Add(ObjectFromXml(childNode, listGenericType));
                        }
                        catch (Exception ex)
                        {
                            Log.Error(string.Concat("Exception loading list element from XML: ", ex, "\nXML:\n", listRootNode.OuterXml));
                        }
                    }
                }
            }
            return list;
        }
        catch (Exception ex2)
        {
            Log.Error(string.Concat("Exception loading list from XML: ", ex2, "\nXML:\n", listRootNode.OuterXml));
            return list;
        }
    }

    public delegate void RefDictDelegate<T, V>(Dictionary<T, V> wanterList, XmlNode entryNode, object debugWanterInfo = null);
    static public Dictionary<IDictionary, Delegate> DictCashe = new Dictionary<IDictionary, Delegate>();
    private static object DictionaryFromXml(XmlNode dictRootNode, Type dictType)
    {
        IDictionary dictionary = Activator.CreateInstance(dictType) as IDictionary;
        Type keyGenericType = dictType.GenericTypeArguments[0];
        Type valueGenericType = dictType.GenericTypeArguments[1];

        bool isDef = typeof(Def).IsAssignableFrom(keyGenericType) || typeof(Def).IsAssignableFrom(valueGenericType);

        if (isDef)
        {
            if (!DictCashe.TryGetValue(dictionary, out Delegate refDelegate))
            {
                MethodInfo methodFuc = MiaoGeneric.GetStaticGenericMethod(typeof(DirectXmlCrossRefLoader), nameof(DirectXmlCrossRefLoader.RegisterDictionaryWantsCrossRef), keyGenericType, valueGenericType);
                //var parameter = methodFuc.GetParameters().Select(w => w.ParameterType).ToArray();
                Type delegateType = typeof(RefDictDelegate<,>).MakeGenericType(keyGenericType, valueGenericType);
                //因为结构和存储必须是泛型，所以必须使用动态调用
                refDelegate = Delegate.CreateDelegate(delegateType, methodFuc);
                DictCashe.Add(dictionary, refDelegate);
            }

            foreach (XmlNode childNode in dictRootNode.ChildNodes)
            {
                refDelegate.DynamicInvoke(dictionary, childNode, dictRootNode);
            }
        }
        else
        {
            foreach (XmlNode childNode2 in dictRootNode.ChildNodes)
            {
                object key = ObjectFromXml(dictRootNode["key"], keyGenericType);
                object value = ObjectFromXml(dictRootNode["value"], valueGenericType);
                dictionary.Add(key, value);

            }
        }
        return dictionary;

    }


    /// <summary>
    /// 反射获取Field,Field预存
    /// </summary>
    /// <param name="type"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    private static FieldInfo GetFieldInfoForType(Type type, string token)
    {
        Dictionary<string, FieldInfo> fieldDictionary = null;
        if (!fieldInfoLookup.TryGetValue(type, out fieldDictionary))
        {
            fieldDictionary = new Dictionary<string, FieldInfo>();
            fieldInfoLookup[type] = fieldDictionary;
        }

        if (!fieldDictionary.TryGetValue(token, out FieldInfo fieldInfo))
        {
            fieldInfo = SearchTypeHierarchy(type, token, BindingFlags.Default);
            fieldDictionary[token] = fieldInfo;
        }
        return fieldInfo;
    }
    /// <summary>
    /// 搜索类型层次结构
    /// 这部分就也是典型的按照名字去检索token，再把数据反射回来。
    /// </summary>
    /// <param name="type"></param>
    /// <param name="token"></param>
    /// <param name="extraFlags"></param>
    /// <returns></returns>
    private static FieldInfo SearchTypeHierarchy(Type type, string token, BindingFlags extraFlags)
    {
        FieldInfo fieldInfo = null;
        while (true)
        {
            fieldInfo = type.GetField(token, extraFlags | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            if (!(fieldInfo == null) || !(type.BaseType != typeof(object)))
            {
                break;
            }
            type = type.BaseType;
        }
        return fieldInfo;
    }


    private static bool ValidateListNode(XmlNode listEntryNode, XmlNode listRootNode, Type listItemType)
    {
        if (listEntryNode is XmlComment)
        {
            return false;
        }
        if (listEntryNode is XmlText)
        {
            Log.Error("XML format error: Raw text found inside a list element. Did you mean to surround it with list item <li> tags? " + listRootNode.OuterXml);
            return false;
        }
        if (listEntryNode.Name != "li" && CustomDataLoadMethodOf(listItemType) == null)
        {
            Log.Error("XML format error: List item found with name that is not <li>, and which does not have a custom XML loader method, in " + listRootNode.OuterXml);
            return false;
        }
        return true;
    }

    private static MethodInfo CustomDataLoadMethodOf(Type type)
    {
        return type.GetMethod("LoadDataFromXmlCustom", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
    }


}

